#include "List.h"
#include "Entry.h"
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <vector>
#include <iomanip>
#include <string>
#include <ctime>

std::string encode(std::string _a){
    //encode simply shifts characters by 5 places (e.g. a:=e)
    int code;
    std::string a;
    char c;

    //read every character and change it
    for (unsigned int i=0;i<_a.length();++i){
        char x=_a.at(i);     //get char at specific position
        code=int(x);         //change it to int
        if(code!=10)code+=5; //encoding

        //if code goes past the character type limits it needs to be returned
        if (code>127){
            code-=128;
        };

        c = char(code);      //change it back to char
        a.push_back(c);      //add it to string
    }
    return a;
}

std::string decode(std::string _a){
    //decode shifts characters back by 5 places (e.g. e:=a)
    int code;
    std::string a;
    char c;
    //same as encode, only it decreases character code by 5
    for (unsigned int i=0;i<_a.length();++i){
        char x=_a.at(i);
        code=int(x);
        if(code!=10)code-=5;
        if (code<0){
            code+=128;
        };
        c = char(code);
        a.push_back(c);
    }
    return a;
}

//destructor
List::~List(){
    Node *p, *q;
    q = first;
    while( q!=NULL){
        p = q;
        q = q->next;
        delete p;
    }
};

//opens and writes entry to input
void List::open(int a)const{
    Node *p;
    p = first;
    int i=0;
    while(p!=NULL&&i<a-1){
        ++i;
        p = p->next;
    };
    std::cout<<p->ent;
}

//saves list
void List::save(std::string name,std::string fpass) const{
    std::string type,text,title,summary,date,tmp;
    Entry::Date dt;
    std::fstream f (name.c_str(), std::fstream::out | std::fstream::trunc);  //opens file and removes its contents

    f<<fpass<<"\n";  //writes password to first line

    //writes entries one-by-one to file
    Node *p;
    p=last;   //read list from the back
    while(p!=NULL){
        //get entry data from node
        type=p->ent->getType();
        title=p->ent->getTitle();
        text=p->ent->getText();
        summary=p->ent->getSummary();
        dt=p->ent->getDate();
        date<<dt;

        tmp=type+"%$"+title+"%$"+summary+"%$"+text+"%$"+date+"%$";  //ads every data of an entry to a string,data separators are '%$'
        tmp=encode(tmp);                                            //encodes text
        f<<tmp<<std::endl;                                          //writes line to file
        p=p->prev;                                                  //go to previous node
    };
    f.close();

}

std::string& operator>>(std::string& s, List& a){
    std::string tmp1=s;
    std::string tmp2;
    std::vector<std::string> v;
    Entry* newEntry;
    Entry::Date date;

    //gets one line which contains one entry, puts it in an array of strings
    //data separators are '%$' so it is forbidden to use this in any input texts
    for(int i=0;i<tmp1.length()-1;++i){
        if((tmp1[i]=='%')&&(tmp1[i+1]=='$')){
            v.push_back (tmp2);
            ++i;
            tmp2="";
        } else {
            tmp2+=tmp1[i];
        };
    };

    //convert date string to date type
    date.year=v[4].substr(0,4);
    date.month=v[4].substr(4,2);
    date.day=v[4].substr(6,2);
    date.hour=v[4].substr(8,2);
    date.min=v[4].substr(10,2);
    date.sec=v[4].substr(12,2);

    //decide which type of entry to create
    switch(v[0][0]){
        case 'T' : newEntry = new Thought(v[0][0],(std::string)v[1],(std::string)v[2],(std::string)v[3],date); break;
        case 'N' : newEntry = new Note(v[0][0],(std::string)v[1],(std::string)v[2],(std::string)v[3],date); break;
        case 'W' : newEntry= new Web(v[0][0],(std::string)v[1],(std::string)v[2],(std::string)v[3],date); break;
        default:
            std::cout<<"Hiba";
    }

    //create node, increase number of nodes in list
    List::Node* newNode;
    ++a.db;

    //add node to list, a new node gets to the first place in line
    if(a.first==NULL) {  //if the list is empty
        newNode = new List::Node(newEntry,NULL,NULL);
        a.last=newNode;
    }else{               //if the list is not full
        newNode = new List::Node(newEntry,a.first,NULL);
        a.first->prev=newNode;
    }
    a.first=newNode;

    return s;
};

std::ostream& operator<<(std::ostream& s, List& a){
    List::Node *p;
    Entry::Date date;
    std::string type,title;

    //table head draw
    std::cout
            << std::left
            <<"  ID | "
            << std::setw(7)<<"Type"
            << std::setw(3)<<" | "
            << std::setw(40)<<"Title"
            << std::setw(3)<<" | "
            <<"Date"
            <<std::endl
            <<std::setw(80)
            <<std::setfill('=')
            <<"="
            <<std::setfill(' ')
            <<std::endl;

    //table body
    p=a.first;
    //step to right position in list according to poz variable in List.h
    for(int j=0;j<a.poz*9;++j){
        if(p->next!=NULL) p=p->next;
    }

    //write 9 list items
    int i=0;
    while (p!=NULL&&i<9){
        ++i;
        //get data
        date=p->ent->getDate();
        title=p->ent->getTitle();
        type=p->ent->getType();
        //translate type
        if (type=="N") type="Note";
        if (type=="T") type="Thought";
        if (type=="W") type="Web";

        std::cout
            << std::left
            << std::setw(4)<<i
            << std::setw(3)<<" | "
            << std::setw(7)<<type
            << std::setw(3)<<" | "
            << std::setw(40)<<title
            << std::setw(3)<<" | "
            <<date;
        p=p->next;
    };
    return s;

}

//adds node to list
void List::add(){
   std::string type,title,text,summary,tmp,date;
    //set up date in date string
      time_t rawtime;
      struct tm * timeinfo;
      char buffer [80];
      time (&rawtime);
      timeinfo = localtime (&rawtime);
      strftime (buffer,80,"%Y%m%d%H%M%S",timeinfo);
      date=buffer;

      std::size_t found;

    char c;
            //conversation to get title, title must be under 50 chars
            std::cout<<"   -What type of entry do you want to add (N-Note T-Thought W-Web address)?  ";
            std::cin>>c;
            do{
                std::cout<<"   -Title: ";
                std::cin>>tmp;
                std::getline(std::cin,title);
                title=tmp+title;
                if(title.length()>50) {
                    std::cout<<"ERROR! Title is longer than 50chars!"<<std::endl<<std::endl;
                };
            }while(title.length()>50);

            //read data depending on type
            switch(c){
                //note type
                case 'N':
                case 'n':
                    type='N';
                    do{
                        std::cout<<"   -Summary: ";
                        std::cin>>tmp;
                        std::getline(std::cin,summary);
                        summary=tmp+summary;
                        if(summary.length()>100) {
                            std::cout<<"ERROR! Summary is longer than 100chars!"<<std::endl<<std::endl;
                        };
                    }while(summary.length()>100);

                        std::cout<<"   -Text: ";
                        std::cin>>tmp;
                        std::getline(std::cin,text);
                        text=tmp+text;


                    tmp=type+"%$"+title+"%$"+summary+"%$"+text+"%$"+date+"%$";
                    tmp>>*this;
                    std::cout<<"--------"<<std::endl<<"---Entry successfully added!"<<std::endl<<"--------"<<std::endl<<std::endl<<std::endl;
                    break;
                //thought type
                case 'T':
                case 't':
                    type='T';
                    summary="";

                    do{
                        std::cout<<"   -Text: ";
                        std::cin>>tmp;
                        std::getline(std::cin,text);
                        text=tmp+text;
                        if(text.length()>500) {
                            std::cout<<"ERROR! Title is longer than 500chars!"<<std::endl<<std::endl;
                        };
                    }while(text.length()>500);

                    tmp=type+"%$"+title+"%$"+summary+"%$"+text+"%$"+date+"%$";
                    tmp>>*this;
                    std::cout<<"--------"<<std::endl<<"---Entry successfully added!"<<std::endl<<"--------"<<std::endl<<std::endl<<std::endl;
                    break;
                //web address type
                case 'W':
                case 'w':
                    type='W';
                    do{
                        std::cout<<"   -Summary: ";
                        std::cin>>tmp;
                        std::getline(std::cin,summary);
                        summary=tmp+summary;
                        if(summary.length()>100) {
                            std::cout<<"ERROR! Summary is longer than 100chars!"<<std::endl<<std::endl;
                        };
                    }while(summary.length()>100);
                        do{
                            std::cout<<"   -Web-address: ";
                            std::cin>>tmp;
                            std::getline(std::cin,text);
                            text=tmp+text;
                            found=text.find("www.");
                            if(found!=0) std::cout<<"Error! I need a web address!"<<std::endl;
                        } while(found!=0);

                    tmp=type+"%$"+title+"%$"+summary+"%$"+text+"%$"+date+"%$";
                    tmp>>*this;

                    std::cout<<"--------"<<std::endl<<"---Entry successfully added!"<<std::endl<<"--------"<<std::endl<<std::endl<<std::endl;
                    break;
                default:
                    std::cout<<"--------"<<std::endl<<"---ERROR! There is no such entry!"<<std::endl<<"--------"<<std::endl<<std::endl<<std::endl;
            }
}
